﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NLog;
using NLog.Config;
using NLog.Targets;

namespace WOMPS
{
    public class FileAccess
    {
        private static Logger logger = LogManager.GetCurrentClassLogger(); 

        public static void SetGlobals()
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start SetGlobals");
            }
            string path = Directory.GetCurrentDirectory();
            Directory.SetCurrentDirectory(path);
            GlobalsWritable gw = ReadConfig(path, "\\Configuration\\womps.config");
            if (gw == null)
            {
                //set path and initialize lists (keep errors when there is no config file
                Globals.HomeDirectory = path;
                Globals.MonitoredDirectories = new List<MonitoredDirectory>();
                Globals.Port = 25;
                Globals.SendTo = new List<EmailAddress>();
                bool isExists = System.IO.Directory.Exists(path + "\\Configuration");
                if (!isExists)
                    System.IO.Directory.CreateDirectory(path + "\\Configuration");
                isExists = System.IO.Directory.Exists(path + "\\Previous");
                if (!isExists)
                    System.IO.Directory.CreateDirectory(path + "\\Previous");
                isExists = System.IO.Directory.Exists(path + "\\Logs");
                if (!isExists)
                    System.IO.Directory.CreateDirectory(path + "\\Logs");
                MessageBox.Show("No Config file found!  The directories need have been created now and you need to create a configuration and save it.", "No Config found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                Globals.HomeDirectory = path;
                Globals.MonitoredDirectories = new List<MonitoredDirectory>();
                Globals.MonitoredDirectories = gw.MonitoredDirectories;
                Globals.Port = gw.Port;
                Globals.SendTo = new List<EmailAddress>();
                Globals.SendTo = gw.SendTo;
                Globals.SentFrom = gw.SentFrom;
                Globals.ServerName = gw.ServerName;
                Globals.ShowExtendedProp = gw.ShowExtendedProp;
                Globals.SMTPServer = gw.SMTPServer;
                Globals.XBMC = gw.XBMC;
                Globals.Log = gw.Log;
                if (!Globals.Log)
                {
                    if (logger.IsInfoEnabled)
                    {
                        logger.Info("Logging Disabled by Config file");
                    }
                    LogManager.DisableLogging();
                }
                else
                {
                    LogManager.EnableLogging();
                }
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End of SetGlobals");
            }
        }

        /// <summary>
        /// Process all files in the directory passed in, recurse on any directories that are found, and process the files they contain.
        /// </summary>
        /// <param name="md">MonitoredDirectory</param>
        /// <returns>List of SeriesFile</returns>
        public static List<SeriesFile> ProcessDirectory(MonitoredDirectory md)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ProcessDirectory; Directory - " + md.Directory);
            }
            List<SeriesFile> sfl = new List<SeriesFile>();
            // Process the list of files found in the directory. 
            string[] fileEntries = Directory.GetFiles(md.Directory);
            foreach (string fileName in fileEntries)
            {
                SeriesFile sf = ProcessFile(fileName, md);
                if (sf != null)
                    sfl.Add(ProcessFile(fileName, md));
            }
            // Recurse into subdirectories of this directory. 
            string[] subdirectoryEntries = Directory.GetDirectories(md.Directory);
            foreach (string subdirectory in subdirectoryEntries)
            {
                MonitoredDirectory newMD = new MonitoredDirectory();
                newMD.Directory = subdirectory;
                newMD.APISource = md.APISource;
                newMD.Divider = md.Divider;
                newMD.HoursToGoBack = md.HoursToGoBack;
                newMD.DateDivider = md.DateDivider;
                sfl.AddRange(ProcessDirectory(newMD));
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End ProcessDirectory; Directory - " + md.Directory);
            }
            return sfl;
        }

        public static List<string> GetPrevious()
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start GetPrevious");
            }
            List<string> files = new List<string>();
            string[] contents = Directory.GetFiles(Globals.HomeDirectory + "\\Previous");
            for (int i = 0; i < contents.Count(); i++)
            {
                FileInfo f = new FileInfo(contents[i]);
                if (f.Extension == ".html")
                {
                    files.Add(f.Name);
                }
            }
            files.Reverse();
            if (logger.IsInfoEnabled)
            {
                logger.Info("End GetPrevious");
            }
            return files;
        }

        /// <summary>
        /// Take the File Name and MonitoredDirectory in which it came from to get the name of show and attempt to get the Airdate
        /// </summary>
        /// <param name="fileName">File Name</param>
        /// <param name="md">MonitoredDirectory</param>
        /// <returns>SeriesFile object</returns>
        private static SeriesFile ProcessFile(string fileName, MonitoredDirectory md)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ProcessFile; filename = " + fileName);
            }
            FileInfo f = new FileInfo(fileName);
            if (!Util.IsRightFileType(f.Extension))
            {
                return null;
            }
            DateTime dt = DateTime.Now.AddHours(-md.HoursToGoBack);
            if (f.LastWriteTime < dt)
            {
                return null;
            }
            if (f.LastWriteTime > DateTime.Now.AddDays(1))//add day to current time in case clocks arnt in sink or something
            {
                return null;
            }
            SeriesFile sf = new SeriesFile();
            string[] sa = f.Name.Split(md.Divider);
            if (sa.Count() <= 0)
            {
                return null;
            }
            sf.SeriesName = sa[0].Trim();
            if (md.APISource == APIType.TVDB)
            {
                for (int i = 0; i < sa.Count(); i++)
                {
                    DateTime? hopeFulAirDate = Util.IsDate(sa[i], md);
                    if (hopeFulAirDate != null)
                    {
                        sf.AiredDate = Convert.ToDateTime(hopeFulAirDate);
                    }

                }
            }
            sf.FileSize = Util.ConvertBytesToMegabytes(f.Length);
            sf.FileType = f.Extension;
            sf.LastModified = f.LastWriteTime;
            if (logger.IsInfoEnabled)
            {
                logger.Info("End ProcessFile; filename = " + fileName);
            }
            return sf;
        }

        /// <summary>
        /// Takes a list of SeriesFiles (processed files) and gets the series information and groups all episodes together
        /// </summary>
        /// <param name="sfl">List of SeriesFile</param>
        /// <returns>List of Series (with episodes if there)</returns>
        public static List<Series> GetSeries(List<SeriesFile> sfl)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start GetSeries");
            } 
            List<Series> sl = new List<Series>();
            for (int i = 0; i < sfl.Count(); i++)
            {

                Series s = WebCalls.GetTVDBSeries(sfl[i]);
                if (s != null)
                {
                    s.FileSize = sfl[i].FileSize;
                    s.FileType = sfl[i].FileType;
                    s.LastModified = sfl[i].LastModified;
                    s.Episodes = new List<Episode>();
                    int? seriesPosition = Util.ShowInList(sl, s.SeriesName);
                    if (seriesPosition == null) //if it equals null then the show has not been added to the array
                    {
                        //see if we can add episode info
                        Util.GetEpisode(ref s, sfl[i]);
                        //add Series to list
                        sl.Add(s);
                    }
                    else
                    {
                        //show is already in list
                        //update series that is list and try and add the episode to it
                        Series previousAddedSeries = sl[Convert.ToInt16(seriesPosition)];
                        Util.GetEpisode(ref previousAddedSeries, sfl[i]);
                        sl[Convert.ToInt16(seriesPosition)] = previousAddedSeries;
                    }
                }
                else
                {
                    //show could not be found
                    Series notfound = new Series();
                    notfound.EpisodeCounter = 1;
                    notfound.FirstAired = sfl[i].LastModified;
                    notfound.LastModified = sfl[i].LastModified;
                    notfound.FileSize = sfl[i].FileSize;
                    notfound.FileType = sfl[i].FileType;
                    notfound.Network = "UNKNOWN";
                    notfound.Overview = "Not found on TVDB.com";
                    notfound.SeriesName = sfl[i].SeriesName + " - Not found on TVDB.com";
                    notfound.Episodes = new List<Episode>();
                    sl.Add(notfound);
                }
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End GetSeries");
            } 
            return sl;
        }

        public static void CreatePrevious(string message)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start CreatePrevious");
            } 
            DateTime dt = DateTime.Now;
            string fileName = dt.Month + "_" + dt.Day + "_" + dt.Year + "-" + dt.Hour + "_" + dt.Minute;
            File.WriteAllText(Globals.HomeDirectory + "\\Previous\\" + fileName + ".html", message);
            if (logger.IsInfoEnabled)
            {
                logger.Info("End CreatePrevious");
            } 
        }

        public static bool WriteConfig()
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start WriteConfig");
            } 
            GlobalsWritable gw = new GlobalsWritable();
            gw.HomeDirectory = Globals.HomeDirectory;
            gw.MonitoredDirectories = Globals.MonitoredDirectories;
            gw.Port = Globals.Port;
            gw.SendTo = Globals.SendTo;
            gw.SentFrom = Globals.SentFrom;
            gw.ServerName = Globals.ServerName;
            gw.ShowExtendedProp = Globals.ShowExtendedProp;
            gw.SMTPServer = Globals.SMTPServer;
            gw.XBMC = Globals.XBMC;
            gw.Log = Globals.Log;
            bool success;
            try
            {
                System.Xml.Serialization.XmlSerializer writer =
                    new System.Xml.Serialization.XmlSerializer(typeof(GlobalsWritable));

                System.IO.StreamWriter file = new System.IO.StreamWriter(
                    Globals.HomeDirectory + "\\Configuration\\womps.config");
                writer.Serialize(file, gw);
                file.Close();
                success = true;
            }
            catch (Exception exc)
            {
                logger.FatalException("WriteConfig", exc);
                success = false;
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End WriteConfig");
            } 
            return success;
        }

        public static GlobalsWritable ReadConfig(string path, string filePath)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ReadConfig");
            } 
            GlobalsWritable gw = new GlobalsWritable();
            try
            {
                System.Xml.Serialization.XmlSerializer reader =
                    new System.Xml.Serialization.XmlSerializer(typeof(GlobalsWritable));
                System.IO.StreamReader file = new System.IO.StreamReader(path + "" + filePath);
                gw = (GlobalsWritable)reader.Deserialize(file);
                file.Close();
            }
            catch (Exception exc)
            {
                logger.FatalException("ReadConfig", exc);
                return null;
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End ReadConfig");
            } 
            return gw;
        }
    }
}
